﻿/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2014 rocky, rockylin@qq.com
 *
 * 
 * NScheduler is free .NET library: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NScheduler is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with NScheduler.  If not, see <http://www.gnu.org/licenses/>.
 *
 * NScheduler是一个自由.NET类库，您可以自由分发、修改其中的源代码或者重新发布它，
 * 新的任何修改后的重新发布版必须同样在遵守LGPL3或更后续的版本协议下发布.
 * 关于LGPL协议的细则请参考COPYING、COPYING.LESSER文件，
 * 您可以在NScheduler的相关目录中获得LGPL协议的副本，
 * 如果没有找到，请连接到 http://www.gnu.org/licenses/ 查看。
 *
 * - Author: Rocky Lin
 * - Contact: rockylin@qq.com
 * - License: GNU Lesser General Public License (LGPL)
 * - Blog and source code availability: https://lightso.codeplex.com/
 */
  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace NScheduler
{
    public class TaskSchedulerBase<T> : TaskScheduler
            where T : IScheduler, new()
    {
        private Thread _processThread;
        private readonly object _lock = new object();

        public TaskSchedulerBase()
        {
            _processThread = new Thread(this.Process);
        }

        private void Process()
        {
            lock (_lock)
            {
                var tasks = GetScheduledTasks();
                if (null != tasks)
                {
                    foreach (var t in tasks)
                    {
                        TryExecuteTask(t);

                        TryDequeue(t);
                    }
                }
            }
        }

        protected override void QueueTask(Task task)
        {
            lock (_lock)
            {
                Scheduler.Add(task);

                if (_processThread.ThreadState.Equals(ThreadState.Stopped))
                {
                    _processThread = new Thread(Process);
                }

                if (!_processThread.IsAlive
                    && !_processThread.ThreadState.Equals(ThreadState.Running))
                {
                    try
                    {
                        _processThread.Start();
                    }
                    catch (System.Exception)
                    {
                        if (!_processThread.ThreadState.Equals(ThreadState.Running))
                        {
                            _processThread = new Thread(Process);
                            _processThread.Start();
                        }
                    }
                }
            }
        }

        protected override bool TryDequeue(Task task)
        {
            Scheduler.Remove(task);

            return true;
        }

        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return Scheduler.ToArray();
        }

        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            if (taskWasPreviouslyQueued)
            {
                if (TryDequeue(task))
                {
                    return base.TryExecuteTask(task);
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return base.TryExecuteTask(task);
            }
        }

        private readonly T _scheduler = new T();
        public T Scheduler
        {
            get
            {
                return _scheduler;
            }
        }
    }
}
